﻿using mozhi.smarterp.Business.Enums;
using Mozhi.Abp.Core.Extensions;
using Mozhi.Abp.Domain.AuthorCenter;
using Mozhi.Abp.Domain.BasicData;
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;

namespace mozhi.smarterp.Business.Purchases
{
    public class PurchaseOrder : DocumentAggregateRoot<PurchaseOrderItem>
    {
        public DateTime? RequiredDate { get; private set; }

        public PurchaseOrderType Type { get; private set; }

        /// <summary>
        /// 采购员
        /// </summary>
        public Guid? PurchaserId { get; private set; }

        public Employee Purchaser { get; private set; }

        /// <summary>
        /// 供应商
        /// </summary>
        public Guid SupplierId { get; private set; }

        public Supplier Supplier { get; private set; }

        /// <summary>
        /// 付款条件
        /// </summary>
        public Guid? PaymentTermId { get; private set; }

        public List<PurchaseOrderAdvancePaymentItem> AdvancePaymentItems { get; private set; }

        private PurchaseOrder() { }

        public PurchaseOrder(Guid id,  string number, DateTime date, DateTime? requiredDate , PurchaseOrderType type, Currency currency , Department department, Employee purchaser, Supplier supplier, Guid? paymentTermId, bool includeTax, string comment)
        {
            Id = id;

            Change(number, date, requiredDate, type, currency, department, purchaser, supplier, paymentTermId, includeTax, comment);

            Items = new List<PurchaseOrderItem>();

            Validate();
        }

        public void Change(string number, DateTime date, DateTime? requiredDate, PurchaseOrderType type, Currency currency, Department department, Employee purchaser, Supplier supplier, Guid? paymentTermId, bool includeTax, string comment)
        {
            base.Change(number, date, includeTax, currency, currency?.ExchangeRate ?? 0, department, comment);

            Purchaser = purchaser;
            Supplier = supplier;

            RequiredDate = requiredDate;

            PurchaserId = Purchaser == null ? default : Purchaser.Id;
            SupplierId = Supplier == null ? default : Supplier.Id;
            DepartmentId = Department == null ? null : Department.Id;
            PaymentTermId = paymentTermId;
            Type = type;
            IncludeTax = includeTax;

            Validate();
        }

        public void SetAdvancePaymentItems(List<PurchaseOrderAdvancePaymentItem> items)
        {
            if (Status != DocumentStatusType.Approved && items.Any(x => x.AdvancePaymentId.HasValue))
                throw new UserFriendlyException("未审核的采购订单不允许关联预付款单", "100000");

            AdvancePaymentItems = AdvancePaymentItems ?? new List<PurchaseOrderAdvancePaymentItem>();

            if (items.IsNullOrEmpty())
                AdvancePaymentItems.Clear();

            AdvancePaymentItems = AdvancePaymentItems ?? new List<PurchaseOrderAdvancePaymentItem>();

            foreach (var item in items)
            {
                var match = AdvancePaymentItems.FirstOrDefault(x => x.Id == item.Id);

                if (match == null)
                {
                    item.CalculateAmount(TotalAmountFr, ExchangeRate);
                    AdvancePaymentItems.Add(item);
                }
                    
                else
                {
                    match.CalculateAmount(TotalAmountFr, ExchangeRate);
                    match.SetPercent(item.AdvancePaymentPercent);
                }
            }
            //删除掉不存在的分录
            var itemIds = items.Select(item => item.Id).ToList();

            var deleted = AdvancePaymentItems.Where(x => !itemIds.Contains(x.Id)).ToList();

            if (deleted.Any(x => x.AdvancePaymentId.HasValue))
                throw new UserFriendlyException("已经付款的预付信息不能删除", "100000");

            deleted.ForEach(x => AdvancePaymentItems.Remove(x));

            if (AdvancePaymentItems.Sum(x => x.AdvancePaymentPercent) > 100)
                throw new UserFriendlyException("预付比例不能大于100%", "100000");

            if (AdvancePaymentItems.Sum(x => x.AdvancePaymentAmountFr) > TotalAmountFr)
                throw new UserFriendlyException("预付金额不能大于订单金额", "100000");

            //重新排序
            int index = 0;
            AdvancePaymentItems.ToList().ForEach(x => x.SetIndex(index++));
        }


        #region
        protected override void Validate()
        {
            base.Validate();

            if (Supplier == null)
                throw new UserFriendlyException("供应商不存在", "100000");

            Supplier.Validate();

            if (Purchaser != null)
                Purchaser.Validate();

            Check.NotDefaultOrNull<DateTime>(RequiredDate, nameof(RequiredDate));

            Check.NotDefaultOrNull<PurchaseOrderType>(Type, nameof(Type));
        }

        protected override void AddOrUpdateItem(PurchaseOrderItem item)
        {
            if (Status == DocumentStatusType.Approved)
                throw new UserFriendlyException("审核单据不允许修改", "100000");

            if (!item.Product.Purchasable)
                throw new UserFriendlyException($"产品：{item.Product.Code}-{item.Product.Name}不允许采购", "100000");

            if (Type == PurchaseOrderType.Standard && item.Product.Type != (int)ProductType.Stock)
                throw new UserFriendlyException($"标准采购只能选择库存类产品", "100000");

            var match = Items.FirstOrDefault(x => x.Id == item.Id);

            if (match == null)
            {
                match = item;

                match.CalculateBaiscUnitQuantity();
                match.CalculateAmount(IncludeTax, ExchangeRate, item.IsGift);
               
                Items.Add(match);
            }

            else
            {
                match.Change(item.Product, item.AuxiliaryUnit, item.ProductAuxiliaryUnit, item.AuxiliaryQuantity, item.Price, item.TaxRate,
                    item.IsGift, item.Remark);

                match.CalculateBaiscUnitQuantity();
                match.CalculateAmount(IncludeTax, ExchangeRate , item.IsGift);
                
            }
        }
        #endregion
    }


    public class PurchaseOrderItem : DocumentEntity
    {
        public bool IsGift { get; private set; }

        private PurchaseOrderItem() { }

        public PurchaseOrderItem(Guid id ,  Product product, Unit purchaseUnit, ProductAuxiliaryUnit productAuxiliaryUnit, decimal purchaseQuantity, decimal price , TaxRate taxRate, bool isGift, string remark)
        {
            Id = id;

            Change(product, purchaseUnit, productAuxiliaryUnit, purchaseQuantity, price, taxRate, isGift, remark);

            SetIsGift(isGift);
            Remark = remark;

            Validate();
        }

        public void Change(Product product, Unit purchaseUnit, ProductAuxiliaryUnit productAuxiliaryUnit, decimal purchaseQuantity, decimal price, TaxRate taxRate, bool isGift, string remark)
        {
            base.Change(product, purchaseUnit, productAuxiliaryUnit, purchaseQuantity, price, taxRate, remark);

            SetIsGift(isGift);
            Remark = remark;

            Validate();
        }

        #region
        protected override void Validate()
        {
            base.Validate();

            if (AuxiliaryUnit == null)
                throw new UserFriendlyException("采购单位不存在", "100000");

            AuxiliaryUnit.Validate();

            if (AuxiliaryQuantity <= 0)
                throw new UserFriendlyException("采购数量必须大于0", "100000");
        }

        private void SetIsGift(bool isGift)
        {
            IsGift = isGift;

            if (isGift)
            {
                TaxRateId = null;
                TaxRateValue = null;
                Price = 0;
            }
        }

        #endregion
    }

    public class PurchaseOrderAdvancePaymentItem : AuditedAggregateRoot<Guid>, IMultiTenant
    {
        public Guid? TenantId { get; private set; }

        public decimal AdvancePaymentPercent { get; private set; }

        public decimal AdvancePaymentAmountFr { get; private set; }

        public decimal AdvancePaymentAmount { get; private set; }

        public DateTime? DueDate { get; set; }

        public DateTime? ExpectedDate { get; set; }

        public Guid? AdvancePaymentId { get; private set; }

        public int Index {  get; private set; }

        private PurchaseOrderAdvancePaymentItem() { }

        public PurchaseOrderAdvancePaymentItem(Guid id, decimal advancePaymentPercent , DateTime? dueDate , DateTime? expectedDate)
        {
            Id = id;
            AdvancePaymentPercent = advancePaymentPercent;
            DueDate = dueDate;
            ExpectedDate = expectedDate;

            Validate();
        }

        public void SetPercent(decimal percent)
        {
            AdvancePaymentPercent = percent;
        }

        public void SetIndex(int index)
        {
            Index = index;
        }

        public void CalculateAmount(decimal orderAmountFr, decimal exchangeRate)
        {
            AdvancePaymentAmountFr = (orderAmountFr * AdvancePaymentPercent/100).ToMoney();
            AdvancePaymentAmount = (AdvancePaymentAmountFr * exchangeRate).ToMoney();

            if (AdvancePaymentAmountFr <= 0 || AdvancePaymentAmount <= 0)
                throw new UserFriendlyException("预付金额必须大于0", "100000");
        }

        #region
        private void Validate()
        {
            if (AdvancePaymentPercent <= 0)
                throw new UserFriendlyException("预付比例必须大于0", "100000");
        }
        #endregion
    }
}
